//
//  VPScanQrCodeView.m
//  qrCodeDemo
//
//  Created by vernepung on 15/11/16.
//  Copyright © 2015年 vernepung. All rights reserved.
//

#import "VPScanQrCodeView.h"
#import "VPScanMaskView.h"
#import <AVFoundation/AVFoundation.h>
#import "UtilsMacro.h"
#import "Helper+Permission.h"
NSString *const VPScanRampingVideoZoom = @"rampingVideoZoom";
CGFloat const VPScanQrCodeViewDefaultWidth = 220.f;
@interface VPScanQrCodeView()<AVCaptureMetadataOutputObjectsDelegate>
@property (strong, nonatomic) UIColor *maskViewBorderColor;
@property (strong, nonatomic) UIColor *maskViewTintColor;
@property (assign, nonatomic) CGFloat maskViewWidth;
@property (assign, nonatomic) CGFloat navHeight;
@property (assign, nonatomic) CGRect cropViewFrame;
@property (assign, nonatomic) BOOL scaled;
@property (nonatomic,strong) VPScanMaskView *maskView;
@property (nonatomic,strong) AVCaptureSession *captureSession;
@property (nonatomic,strong) AVCaptureVideoPreviewLayer *videoPreviewLayer;
@property (nonatomic,strong) AVCaptureMetadataOutput *metadataOutput;
@property (strong, nonatomic) AVCaptureDeviceInput *deviceInput;
@property (strong, nonatomic) AVCaptureDevice *captureDevice;
@end


@implementation VPScanQrCodeView

#pragma mark - life cycle
- (instancetype)initWithFrame:(CGRect)frame maskViewWidth:(CGFloat)width maskBorderColor:(UIColor *)color tintColor:(UIColor *)tintColor andNavHeight:(CGFloat)heihgt {
    self = [super initWithFrame:frame];
    if (self) {
        self.backgroundColor = [UIColor colorWithRed:0 green:0 blue:0 alpha:.75];
        _maskViewWidth = width;
        _maskViewBorderColor = color;
        _maskViewTintColor = tintColor;
        _navHeight = heihgt;
        _maxZoom = 3.5f;
        
        UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(scanDoubleTapped)];
        tapGesture.numberOfTapsRequired = 2;
        [self.maskView addGestureRecognizer:tapGesture];
    }
    return self;
}

- (void)removeFromSuperview {
    [super removeFromSuperview];
    [self invalidateScan];
}

- (void)willMoveToSuperview:(UIView *)newSuperview {
    [super willMoveToSuperview:newSuperview];
    if (newSuperview) {
        [self initCapture];
    }
}

#pragma mark - private function
- (void)vpCaptureSessionInterruptionEnded {
    if (_captureSession && _captureSession.isRunning) {
        [_captureSession stopRunning];
    }
    [_captureSession startRunning];
}

- (void)vpAVCaptureSessionStarted {
    if (self.delegate && [self.delegate respondsToSelector:@selector(vpCaptureRunningCompleted)]) {
        dispatch_async(dispatch_get_main_queue(), ^{
            //            [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(vpCaptureSessionInterruptionEnded) name:AVCaptureSessionInterruptionEndedNotification object:nil];
            [self.delegate vpCaptureRunningCompleted];
        });
    }
}

- (void)initCapture {
    if (self.tag == 0){
        self.tag = NSIntegerMax;
        [Helper checkingVideoPermissionWithCompleteBlock:^(BOOL result, AVAuthorizationStatus status) {
            if (result || status == AVAuthorizationStatusNotDetermined) {
                [self.layer insertSublayer:self.videoPreviewLayer atIndex:0];
                [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(vpAVCaptureSessionStarted) name:AVCaptureSessionDidStartRunningNotification object:nil];
                [self.captureSession startRunning];
            }else{
                if (self.delegate && [self.delegate respondsToSelector:@selector(vpScanQrCodeWithError:)]) {
                    dispatch_async(dispatch_get_main_queue(), ^{
                        [self.delegate vpScanQrCodeWithError:VPQrCodeErrorCantOpenCapture];
                    });
                }
            }
        }];
    }
}

- (void)invalidateScan {
    if (_captureSession && self.captureSession.isRunning) {
        if (self.maskView.canScale) {
            [self.captureDevice removeObserver:self forKeyPath:VPScanRampingVideoZoom];
        }
        [self.captureSession removeInput:self.deviceInput];
        self.deviceInput = nil;
        [self.metadataOutput setMetadataObjectsDelegate:nil queue:NULL];
        [self.captureSession removeOutput:self.metadataOutput];
        self.metadataOutput = nil;
        
        [self.captureSession stopRunning];
        self.captureSession = nil;
        [self.maskView stopAnimation];
        [[NSNotificationCenter defaultCenter] removeObserver:self];
    }
}

- (void)scanDoubleTapped {
    self.maskView.userInteractionEnabled = NO;
    self.scaled = !self.scaled;
    if ([self.captureDevice lockForConfiguration:nil]) {
        if (self.scaled){
            [self.captureDevice rampToVideoZoomFactor:self.maxZoom withRate:50];
        }else{
            [self.captureDevice rampToVideoZoomFactor:1 withRate:50];
        }
        [self.captureDevice unlockForConfiguration];
    }
}

#pragma mark - AVCaptureMetadataOutputObjectsDelegate
- (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputMetadataObjects:(NSArray *)metadataObjects fromConnection:(AVCaptureConnection *)connection {
    if (!metadataObjects || metadataObjects.count <= 0)return;
    AVMetadataMachineReadableCodeObject *codeObj = [metadataObjects objectAtIndex:0];
    if (codeObj && [[codeObj type] isEqualToString:AVMetadataObjectTypeQRCode]) {
        [self invalidateScan];
        if (self.delegate && [self.delegate respondsToSelector:@selector(vpScanQrCodeCompletedWithResult:)]) {
            [self.delegate vpScanQrCodeCompletedWithResult:codeObj.stringValue];
        }
    }
}

#pragma mark - KVO
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context {
    if ([keyPath isEqualToString:VPScanRampingVideoZoom]) {
        NSInteger newValue = [[change objectForKey:@"new"] integerValue];
        if (newValue) {
            self.maskView.userInteractionEnabled = NO;
        }else{
            self.maskView.userInteractionEnabled = YES;
        }
    }
}

#pragma mark - public function
- (void)startScanQrCode {
    if (self.maskView.superview) {
        return;
    }
    if (self.maskViewWidth <= 0) {
        self.maskViewWidth = VPScanQrCodeViewDefaultWidth;
    }
    [self.superview addSubview:self.maskView];
    [self setRectOfInterest];
    [UIView animateWithDuration:.25 animations:^{
        self.maskView.layer.opacity = 1;
        self.maskView.layer.transform = CATransform3DIdentity;
    } completion:^(BOOL finished) {
        [UIView animateWithDuration:.25 animations:^{
            self.videoPreviewLayer.opacity = 1;
        }];
    }];
}

- (void)setRectOfInterest {
    CGSize size = self.bounds.size;
    self.cropViewFrame = CGRectMake((size.width - self.maskViewWidth) / 2, (size.height - self.maskViewWidth) / 2 - self.navHeight , self.maskViewWidth, self.maskViewWidth);
    // 识别范围 > 显示识别范围
    CGRect temp = self.cropViewFrame;
    temp.origin.x -= 10;
    temp.origin.y -= 10;
    temp.size.width += 20;
    temp.size.height += 20;
    self.metadataOutput.rectOfInterest = [self.videoPreviewLayer metadataOutputRectOfInterestForRect:temp];
}

#pragma mark - getter && setter
- (AVCaptureVideoPreviewLayer *)videoPreviewLayer {
    if (!_videoPreviewLayer) {
        _videoPreviewLayer = [[AVCaptureVideoPreviewLayer alloc]initWithSession:self.captureSession];
        [_videoPreviewLayer setVideoGravity:AVLayerVideoGravityResizeAspectFill];
        [_videoPreviewLayer setFrame:self.layer.bounds];
        _videoPreviewLayer.opacity = 0.;
    }
    return _videoPreviewLayer;
}

- (AVCaptureSession *)captureSession {
    if (!_captureSession) {
        self.captureDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
        NSError *error;
        self.deviceInput = [[AVCaptureDeviceInput alloc] initWithDevice:self.captureDevice error:&error];
        if (error) {
            _captureSession = nil;
        }else{
            [self.captureDevice addObserver:self forKeyPath:VPScanRampingVideoZoom options:NSKeyValueObservingOptionNew context:nil];
            if (self.captureDevice.activeFormat.videoMaxZoomFactor >= self.maxZoom){
                self.maskView.userInteractionEnabled = YES;
                self.maskView.canScale = YES;
            }else if (self.captureDevice.activeFormat.videoMaxZoomFactor > 1.0) {
                self.maxZoom = self.captureDevice.activeFormat.videoMaxZoomFactor;
                self.maskView.userInteractionEnabled = YES;
                self.maskView.canScale = YES;
            }else{
                self.maskView.userInteractionEnabled = NO;
                self.maskView.canScale = NO;
                [self.captureDevice removeObserver:self forKeyPath:VPScanRampingVideoZoom];
            }
            [self.captureDevice lockForConfiguration:nil];
            if ([self.captureDevice isFocusPointOfInterestSupported] && [self.captureDevice isFocusModeSupported:AVCaptureFocusModeContinuousAutoFocus] ) {
                [self.captureDevice setFocusMode:AVCaptureFocusModeContinuousAutoFocus];
            }
            [self.captureDevice unlockForConfiguration];
            self.metadataOutput = [[AVCaptureMetadataOutput alloc]init];
            [self.metadataOutput connectionWithMediaType:AVMediaTypeMetadata];
            _captureSession = [[AVCaptureSession alloc] init];
            _captureSession.sessionPreset = AVCaptureSessionPreset1920x1080;
            
            if ([_captureSession canAddInput:self.deviceInput]){
                [_captureSession addInput:self.deviceInput];
            }
            if ([_captureSession canAddOutput:self.metadataOutput]) {
                [_captureSession addOutput:self.metadataOutput];
            }
            [self.metadataOutput setMetadataObjectsDelegate:self queue:dispatch_get_main_queue()];
            [self.metadataOutput setMetadataObjectTypes:@[AVMetadataObjectTypeQRCode]];
        }
    }
    return _captureSession;
}

- (UIView *)maskView {
    if (!_maskView) {
        _maskView = [[VPScanMaskView alloc] initWithFrame:self.bounds scanViewWidth:self.maskViewWidth];
        _maskView.borderColor = self.maskViewBorderColor;
        _maskView.tintColor = self.maskViewTintColor;
        _maskView.canScale = NO;
        _maskView.userInteractionEnabled = NO;
        _maskView.backgroundColor = [UIColor clearColor];
        _maskView.layer.opacity = 0.f;
        _maskView.layer.transform = CATransform3DMakeScale(1.5, 1.5, 1.5);
    }
    return _maskView;
}

@end
